package server;
import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;
import msgs.*;
import java.io.*;


import java.security.*;
/**
 * Adds new clients to the system
 * Team 9: Andrew Hayworth, Brian Parrella, Ryan Kortmann, Nina Papa
 * @author Andrew Hayworth
 */
public class NewClientConnection extends Thread implements TTConstants {
	private ClientMsg cmsg;
	
	public NewClientConnection(ClientMsg cmsg) {
		this.cmsg = cmsg;
	}
	
	public void run() {
		// first auth
		if (!(authenticate(cmsg.getName(), cmsg.getPwd())) || TTServer.banHammer.contains(cmsg.getName()) || TTServer.connTable.containsKey(cmsg.getName())) {
			cmsg.setResponse(Responses.DENY);
			ClientSender.outQ.add(cmsg);
			return;
		}
		
		// ok, add them to the database(s), set the responses...
		
		byte[] key = md5(cmsg.getName());
		cmsg.setClientKey(key);
		cmsg.setResponse(Responses.OK);
		synchronized (TTConstants.lock) {
			TTServer.connTable.put(cmsg.getName(),new ConnectedUser(cmsg));
			
 		}
		
		ClientSender.outQ.add(cmsg);
		
		// fill in whom they're interested in.
		ArrayList<String> al = BLWorker.getBL(cmsg.getName());
		if (al != null) {		
			for (String name : al) {
				if (!(TTServer.interestedIn.containsKey(name))) {
					ArrayList<String> n = new ArrayList<String>();
					n.add(cmsg.getName());
					synchronized(TTConstants.lock) {
						TTServer.interestedIn.put(name, n);
					}
				}
				else {
					synchronized(TTConstants.lock) {
						TTServer.interestedIn.get(name).add(cmsg.getName());
					}
				}
			}
		}	
		
		//now we find out who's interested in us, and tell them we're online!
		if (TTServer.interestedIn.containsKey(cmsg.getName())) {
			ArrayList<String> al2 = TTServer.interestedIn.get(cmsg.getName());
			ClientMsg cm;
			for (String s : al2) {
				// we only actually want to send out an online notice if person whom needs to know is ACTUALLY online...
				// dont know how I missed this before ....
				if (TTServer.connTable.containsKey(s)) {
					cm = new ClientMsg(TTServer.connTable.get(s), Actions.ONLINE_NOTICE);
					cm.setUser(cmsg.getName());
					ClientSender.outQ.add(cm);
				}
			}
		}
		
		
		
		
		//check if they have offline pms, and if they do, send them
		if (TTServer.offlinePm.containsKey(cmsg.getName())) {
			try {
				// we need to give the client a few seconds to get set up
				Thread.sleep(3000);
			}
			catch (InterruptedException e) {}
			System.out.println("We have offline PMs for this user");
			Hashtable<String, ArrayList<String>> ht = (Hashtable<String, ArrayList<String>>) TTServer.offlinePm.remove(cmsg.getName());
			Set<String> s = (Set<String>) ht.keySet();
			ArrayList<String> msgs;
			for (String name : s) {
				msgs = (ArrayList<String>) ht.get(name);
				for (String msg: msgs) {
					ClientSender.outQ.add((ClientMsg) new OfflinePMMsg(new ConnectedUser(cmsg), TTConstants.Actions.OFFLINE_MSG, name, msg, cmsg.getName() ) );
				}
			}
			TTServer.writeObject(new File("data/offlinePm.dat"), TTServer.offlinePm);
		}
	}
	
	private boolean authenticate(String uname, String pwd) {
		Hashtable<String, String> login = new Hashtable<String, String>(5);
        login.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        login.put(Context.PROVIDER_URL, "ldap://ldap.rit.edu/ou=people,dc=rit,dc=edu?uid?sub");
        login.put(Context.SECURITY_AUTHENTICATION, "simple");
        login.put(Context.SECURITY_PRINCIPAL, "uid=" + uname + ", ou=people, dc=rit, dc=edu");
        login.put(Context.SECURITY_CREDENTIALS, pwd);
        try {
        	DirContext ctx = new InitialDirContext(login);
        	ctx.close();
        }
        catch (NamingException e) { return false; }
        return true;
	}
	
	private byte[] md5(String name) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
	        md.update(name.getBytes());
	        byte[] key = md.digest();
	        return key;
		}
		catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			return null;
		}
	}
}
